// var a = 123;
// console.log(a);
// function fn() {
//   console.log(666)
// }
// let b = true;
// let c = 'qqq';
// a = true;
var a: number = 1233.3242;
// a = ''

let b: string = '';

const c: boolean = true;
// 以上三个是基本数据类型


// 联合类型
let d: number | string = 123;
d = 333;
d = 'qqq';



// let arr = [1, 2, true];

// 创造一个数组 数组中的每一项都得是数字
let arr: (number | boolean)[] = [1, 2, true]
// let arr: Array<number> = [1, 2, 3, '']
// let arr: Array<number|string> = [1, 2, 3, '']


// 元组
// 规定了数量和类型的数组
let arr2: [number, number] = [1, 2]

let arr3: [number, string, boolean] = [1, '', true]
arr3[0] = 100;

// 枚举  其实就是一个对象  code code == 0 ?'man'
enum Person {
  man = 0,
  women = 1,
  girl = 2,
  boy = 3
}
console.log(Person)
for (let k in Person) {
  console.log(k)
}

enum qqq {
  play = 100,
  eat = 200,
  sleep = 300
}




// 任意数据类型 跟写JS就一样了
let aa: any = 123;
aa = true;


// null undefined

let arr4: number[] = [];
let a2: number | undefined | null = 123;
a2 = undefined;
a2 = null;

// let a3: null = null;
// a3=1

// void 没有任何类型
// 当前的函数没有任何返回
function aaa(): void {
  // return undefined
  // return null

}

function bbb(): number {
  return 234
}

function f(a: number, b: number): number {
  return a + b
}

f(1, 3)
f(1, 2)


function f2(a: number, b: string): any {
  return a + b
}
f2(1, '3')

// b 可以不传
// 可选参数只能放到最后
function f3(a: number, b?: number, c?: string): string | number {
  return a + b
}
f3(1)

// 默认值
// 默认值和可选符号不能同时存在
function f4(a: number, b?: number): void {
  b = b || 10
  console.log(a + b)
}
f4(1, 2)
f4(1)
function f5(a: number, b: number = 10): any {
  console.log(a + b)
}
f5(1)

// 剩余运算符
function f6(a: number, ...b: number[]) {
  console.log(a, b)
}
f6(1, 2, 3, 4, 5, 6, 7, 8, 9)

// 重载

// let obj = {
//   name:'',
//   age:0
// }
let obj: any = {}
// 函数的重载
// 就是给一个函数 指定了集中可执行的方式
function f7(a: number, b: number): void;
function f7(a: string): void;
function f7(a: any) {
  if (typeof a == 'number') {
    obj.age = a;
  } else {
    obj.name = a
  }
}
f7(1, 2)
f7('zhufeng')
// f7(true)


class School {
  // public  不写 默认就是public
  // protected 受保护的属性 在当前类及子类上是可以访问的
  // private 私有属性 在当前类的外部是不允许访问的
  private name: string // 实力上的属性需要在这个地方声明类型
  protected name2: string
  static age: number = 100 // 类的静态属性的赋值于类型声明
  constructor() {
    this.name = "珠峰"
  }
  getName(): string {
    return this.name
  }
}
let s1 = new School();
// console.log(s1.name)
class School2 extends School {
  // readonly 只读属性 只能获取 不能赋值
  public readonly age2: number
  getName2() {
    // console.log(this.name)
    console.log(this.name2)
  }
  changeAge(n) {
    // this.age2 = n
  }
}
let s2 = new School2()
s2.getName2()


// 接口  不是前后端交互的接口  是ts的一个语法

// 表示行为的规范 或者 对象的描述
// 接口中的分割 可以是逗号 或者 分号 或者 啥也不写
interface ISpeak {
  name: string,
  age: number,
  sex?: number // 表示 sex可以有 也可以没有
}

let obj5: ISpeak = {
  name: "zhufeng",
  age: 12,
  sex: 1
}
let obj6: ISpeak = {
  name: "zhufeng",
  age: 12
}

// ISpeak2 就是说   使用这个接口的对象 必须有name和age
// 其他属性不限
interface ISpeak2 {
  name: string,
  age: number,
  talk(name: string, str: string): string,// 对象中必须有talk函数 返回值得是一个字符串
  [key: string]: any
}

let obj7: ISpeak2 = {
  name: 'zhufeng',
  age: 12,
  talk(a: string, b: string) {
    return a + b
  },
  q: 1,
  b: 2
}
obj7.talk('qq', 'ww')


// 行为的约束
interface Ieat {
  eat(): void
}
interface Iplay {
  play(a: string): string
}

// 类去实现接口 让当前的类 遵循接口
class Animal implements Ieat, Iplay {
  eat() {
    console.log(666)
  }
  play(name: string) {
    return name
  }
  qq() {

  }
}

let ani = new Animal()



interface Student {
  learn(a: string): string,
  readonly age: number
}

interface YouEr extends Student {
  play(): void
}

let s: YouEr = {
  age: 123,
  play() {
    console.log('play')
  },
  learn(type: string) {
    return 'hao'
  }
}
console.log(s.age)


// 函数类型的接口
interface Ifn {
  (age: number, sex: number, name: string): number
}

let f1: Ifn = function (a: number, b: number, c: string) {
  console.log(c)
  return a + b
}
f1(1, 2, '')




// 泛型
/* function createAry(length: number, value: string | number): Array<string | number> {
  let ary: (string | number)[] = [];
  for (let i = 0; i < length; i++) {
    ary[i] = value + ''
  }
  return ary
}
console.log(createAry(3, '2'))
console.log(createAry(3, 2)) */

function createAry<T>(length: number, value: T): Array<T> {
  let ary: T[] = [];
  for (let i = 0; i < length; i++) {
    ary[i] = value
  }
  return ary
}
console.log(createAry<string>(3, '2'))
console.log(createAry<number>(3, 2))

interface Iobj {
  name: string,
  age: number
}

console.log(createAry<Iobj>(3, { name: 'q', age: 1 }))

class MyAry<T, W, Q>{
  private list: T[] = [];
  add(value: T) {
    this.list.push(value)
  }
}
let ary2 = new MyAry<number, string, boolean>()

ary2.add(12)


// 接口的泛型
interface IList<T> {
  list: T[]
}

let list123: IList<number> = {
  list: [1, 2]
}

let list124: IList<string> = {
  list: ['']
}
let list125: IList<{ name: string, age: number }> = {
  list: [{ name: '', age: 1 }]
}



